package com.leyou.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.RegexUtils;
import com.leyou.dto.UserDTO;
import com.leyou.mapper.TbUserMapper;
import com.leyou.pojo.TbUser;
import com.leyou.service.TbUserService;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static com.leyou.common.constants.RocketMQConstants.TAGS.VERIFY_CODE_TAGS;
import static com.leyou.common.constants.RocketMQConstants.TOPIC.SMS_TOPIC_NAME;

@Service
public class TbUserServiceImpl extends ServiceImpl<TbUserMapper, TbUser> implements TbUserService {

    // TODO 验证用户名或者手机号是否存在
    @Override
    public Boolean checkUserData(String data, Integer type) {
        QueryWrapper<TbUser> queryWrapper = new QueryWrapper<>();
        switch (type) {
            case 1:
                queryWrapper.lambda().eq(TbUser::getUsername, data);
                break;
            case 2:
                queryWrapper.lambda().eq(TbUser::getPhone, data);
                break;
            default:
                throw new LyException(ExceptionEnum.INVALID_PARAM_ERROR);
        }
        int count = this.count(queryWrapper);
        // 如果为0，表示数据库没有，返回true，可用
        return count == 0;
    }

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    private static final String KEY_PREFIX = "ly:user:phone:";

    // TODO 发送短信验证码 存入redis，设置失效时间
    @Override
    public void sendCode(String phone) {
        // 校验手机格式
        if (!RegexUtils.isPhone(phone)) {
            throw new LyException(ExceptionEnum.INVALID_PHONE_NUMBER);
        }
        // 随机生成一个验证码，6位
        String code = RandomStringUtils.randomNumeric(6);
        // 保存验证码到redis中  失效时间
        redisTemplate.opsForValue().set(KEY_PREFIX + phone, code, 30, TimeUnit.MINUTES);
        System.out.println(redisTemplate.opsForValue().get(KEY_PREFIX + phone));
        // 向RocketMq中发送信息，构建一个map，phone和code
        Map<String, String> map = new HashMap<>();
        map.put("phone", phone);
        map.put("code", code);
        rocketMQTemplate.convertAndSend(SMS_TOPIC_NAME + ":" + VERIFY_CODE_TAGS, map);
    }

    @Autowired
    private BCryptPasswordEncoder encoder;

    @Override
    public void register(TbUser user, String code) {
        // 验证码验证
        String s = redisTemplate.opsForValue().get(KEY_PREFIX + user.getPhone());
        if (!StringUtils.equals(s, code)) {
            throw new LyException(ExceptionEnum.INVALID_VERIFY_CODE);
        }
        // 密码加密
        String encode = encoder.encode(user.getPassword());
        user.setPassword(encode);
        // 数据保存
        TbUser tbUser = BeanHelper.copyProperties(user, TbUser.class);
        try {
            this.save(tbUser);
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
    }

    @Autowired
    private TbUserMapper tbUserMapper;
    /**
     * 用户登录时，查询用户，密码验证
     * @param username
     * @param password
     * @return
     */
    @Override
    public UserDTO queryUserByUsernameAndPassword(String username, String password) {
        // 根据用户名查询用户
        TbUser tbUser =tbUserMapper.getUserByUsername(username);
        if (tbUser==null){
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        // 校验密码
        // 内部校验流程：根据 加密后的密码，推测出salt，然后使用salt重新加密用户输入的，最后比对
        // 参数一：用户输入的密码 参数二：数据库存储的密码
        boolean matches = encoder.matches(password,tbUser.getPassword());
        if (!matches){
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        return BeanHelper.copyProperties(tbUser,UserDTO.class);
    }
}
